﻿#include "pch.h"
#include "sbhs.h"

#ifndef k_eq
#define k_eq(a,b)		(((a)+0.0001f>(b)) && ((a)-0.0001f<(b)))
#endif

//////////////////////////////////////////////////////////////////////////
// 변수

// 검사
void k_var_check(kVar* p)
{
	if (p->type == KTYPE_NULL)
		p->rv.p = NULL;
}

// 제로
void k_var_zero(kVar* p)
{
	p->type = KTYPE_NULL;
	p->rv.p = NULL;
}

// 로드
void k_var_load(kVar* p)
{
	if (k_var_is_ref(p))
	{
		kBase* self = (kBase*)p->rv.p;
		k_base_load(self);
	}
}

// 언로드
void k_var_unload(kVar* p)
{
	if (k_var_is_ref(p))
	{
		kBase* self = (kBase*)p->rv.p;
		k_base_unload(self);

#if _SB_DEBUG_
		k_var_zero(p);
#endif
	}
}

// 문자열
const char* k_var_tos(const kVar* p, char* buf, kint size, kint* outlen)
{
	khOpTosFunc opf = (khOpTosFunc)k_type_get_op(p->type, KHOP_TOS);
	if (opf)
		return opf(p, buf, size, outlen);
	else
	{
		// 연산자 없음
		return k_type_get_name(p->type);
	}
}

// 다른 변수 할당
void k_var_agn(kVar* p, const kVar* o)
{
	*p = *o;
}

// 베이스 할당
void k_var_agn_base(kVar* p, kBase* o)
{
	p->type = k_base_get_type(o);
	p->rv.p = o;
}

// 타입 및 포인터
void k_var_agn_type(kVar* p, kType type, kBase* ptr)
{
	p->type = type;
	p->rv.p = ptr;
}

// 복사
void k_var_set(kVar* p, const kVar* o)
{
	k_var_agn(p, o);
	k_var_load(p);
}

// 베이스+타입
void k_var_set_type(kVar* p, kType type, kBase* ptr)
{
	k_base_load(ptr);
	k_var_agn_type(p, type, ptr);
}

// 널
void k_var_set_null(kVar* p)
{
	p->type = KTYPE_NULL;
	p->rv.p = NULL;
}

// 파라미터
void k_var_set_param(kVar* p, const khParamDesc* o)
{
	p->type = KTYPE_PARAM;
	p->rv.cp = o;
}

// 포인터
void k_var_set_ptr(kVar* p, kpointer o)
{
	p->type = KTYPE_POINTER;
	p->rv.p = o;
}

// 불린
void k_var_set_bool(kVar* p, kbool o)
{
	p->type = KTYPE_BOOL;
	p->rv.i = o;
}

// 정수
void k_var_set_int(kVar* p, kint o)
{
	p->type = KTYPE_INT;
	p->rv.i = o;
}

// 롱
void k_var_set_long(kVar* p, klong o)
{
	p->type = KTYPE_LONG;
	p->rv.i64 = o;
}

// 실수
void k_var_set_float(kVar* p, float o)
{
	p->type = KTYPE_FLOAT;
	p->rv.f = o;
}

// 더블
void k_var_set_double(kVar* p, double o)
{
	p->type = KTYPE_DOUBLE;
	p->rv.dbl = o;
}

// 베이스
void k_var_set_base(kVar* p, kBase* o)
{
	k_base_load(o);
	k_var_agn_base(p, o);
}

// 문자열
void k_var_set_str(kVar* p, const char* str, kint len)
{
	kuint sym = k_symtry(str);
	if (sym != 0)
	{
		p->type = KTYPE_SYMBOL;
		p->rv.u = sym;
	}
	else
	{
		p->type = KTYPE_STR;
		p->rv.p = k_redstr_new(str, len);
	}
}

// 유니코드 문자열
void k_var_set_wcs(kVar* p, const kwchar* str, kint len)
{
	p->type = KTYPE_WCS;
	p->rv.p = k_redwcs_new(str, len);
}

// 심볼
void k_var_set_sym(kVar* p, kuint o)
{
	p->type = KTYPE_SYMBOL;
	p->rv.u = o;
}

// 심볼
void k_var_set_sym_flex(kVar* p, const char* str)
{
	p->type = KTYPE_SYMBOL;
	p->rv.u = k_symflx(str);
}

// 심볼
void k_var_set_sym_static(kVar* p, const char* str)
{
	p->type = KTYPE_SYMBOL;
	p->rv.u = k_symstt(str);
}

// 편안한 심볼
kcham k_var_try_sym(kVar* p, const char* str)
{
	p->rv.u = k_symtry(str);
	if (p->rv.u == 0)
	{
		p->type = KTYPE_NULL;
		return FALSE;
	}
	else
	{
		p->type = KTYPE_SYMBOL;
		return TRUE;
	}
}

// 널
kcham k_var_is_null(const kVar* p)
{
	return p->type == KTYPE_NULL;
}

// 널아님
kcham k_var_is_not_null(const kVar* p)
{
	return p->type != KTYPE_NULL;
}

// 파라미터
kcham k_var_is_param(const kVar* p)
{
	return p->type == KTYPE_PARAM;
}

// 포인터
kcham k_var_is_ptr(const kVar* p)
{
	return p->type == KTYPE_POINTER;
}

// 불린
kcham k_var_is_bool(const kVar* p)
{
	return p->type == KTYPE_BOOL;
}

// 정수
kcham k_var_is_int(const kVar* p)
{
	return p->type == KTYPE_INT;
}

// 롱
kcham k_var_is_long(const kVar* p)
{
	return p->type == KTYPE_LONG;
}

// 실수
kcham k_var_is_float(const kVar* p)
{
	return p->type == KTYPE_FLOAT;
}

// 더블
kcham k_var_is_double(const kVar* p)
{
	return p->type == KTYPE_DOUBLE;
}

// 심볼
kcham k_var_is_sym(const kVar* p)
{
	return p->type == KTYPE_SYMBOL;
}

// 아스키 문자열
kcham k_var_is_str(const kVar* p)
{
	return p->type == KTYPE_STR;
}

// 유니코드 문자열
kcham k_var_is_wcs(const kVar* p)
{
	return p->type == KTYPE_WCS;
}

// 테이블
kcham k_var_is_tbl(const kVar* p)
{
	return p->type == KTYPE_TBL;
}

// 가상 함수
kcham k_var_is_fn(const kVar* p)
{
	return p->type == KTYPE_FN;
}

// 숫자
kcham k_var_test_num(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id >= KTYPE_INT && id <= KTYPE_DOUBLE;
}

// 문자열
kcham k_var_test_str(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id == KTYPE_SYMBOL || id == KTYPE_STR;
}

// 정수형
kcham k_var_test_int(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id >= KTYPE_BOOL && id <= KTYPE_LONG;
}

// 실수형
kcham k_var_test_real(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id == KTYPE_FLOAT || id == KTYPE_DOUBLE;
}

// 키
kcham k_var_test_key(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id == KTYPE_INT || id == KTYPE_SYMBOL;
}

// 함수
kcham k_var_test_call(const kVar* p)
{
	kuint id = (kuint)p->type;
	return id == KTYPE_PARAM || id == KTYPE_FN;
}

// 타입
kcham k_var_test_type_of(const kVar* p, kType type)
{
	return p->type == type;
}

// 값 형식
kcham k_var_is_value(const kVar* p)
{
	return k_type_is_value(p->type);
}

// 참조 형식
kcham k_var_is_ref(const kVar* p)
{
	return k_type_is_ref(p->type);
}

// 베이스 오브
kcham k_var_safe_type(const kVar* p, kType type, kBase** o)
{
	if (p->type != type)
		return FALSE;
	else
	{
		*o = (kBase*)p->rv.p;
		return TRUE;
	}
}

// 파라미터
kcham k_var_safe_param(const kVar* p, khParamDesc** o)
{
	if (p->type != KTYPE_PARAM)
		return FALSE;
	else
	{
		*o = (khParamDesc*)p->rv.p;
		return TRUE;
	}
}

// 포인터
kcham k_var_safe_ptr(const kVar* p, kpointer* o)
{
	if (p->type != KTYPE_POINTER)
		return FALSE;
	*o = p->rv.p;
	return TRUE;
}

// 불린
kcham k_var_safe_bool(const kVar* p, kbool* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = FALSE;
			break;
		case KTYPE_BOOL:
			*o = p->rv.b;
			break;
		case KTYPE_INT:
			*o = p->rv.i != 0;
			break;
		case KTYPE_LONG:
			*o = p->rv.i64 != 0;
			break;
		default:
			return FALSE;
	}
	return TRUE;
}

// 정수
kcham k_var_safe_int(const kVar* p, kint* o)
{
	if (p->type != KTYPE_INT)
		return FALSE;
	*o = p->rv.i;
	return TRUE;
}

// 롱
kcham k_var_safe_long(const kVar* p, klong* o)
{
	if (p->type != KTYPE_LONG)
		return FALSE;
	*o = p->rv.i64;
	return TRUE;
}

// 실수
kcham k_var_safe_float(const kVar* p, float* o)
{
	if (p->type != KTYPE_FLOAT)
		return FALSE;
	*o = p->rv.f;
	return TRUE;
}

// 더블
kcham k_var_safe_double(const kVar* p, double* o)
{
	if (p->type != KTYPE_DOUBLE)
		return FALSE;
	*o = p->rv.dbl;
	return TRUE;
}

// 심볼
kcham k_var_safe_sym(const kVar* p, kuint* o)
{
	if (p->type != KTYPE_SYMBOL)
		return FALSE;
	*o = p->rv.u;
	return TRUE;
}

// 심볼
kcham k_var_safe_sym_str(const kVar* p, const char** str, kint* len)
{
	if (p->type != KTYPE_SYMBOL)
		return FALSE;
	if (str)
		*str = k_symunstr(p->rv.u);
	if (len)
		*len = (kint)k_symunlen(p->rv.u);
	return TRUE;
}

// 베이스
kcham k_var_safe_base(const kVar* p, kBase** o)
{
	if (!k_var_is_ref(p))
		return FALSE;
	*o = (kBase*)p->rv.p;
	return TRUE;
}

// 스트링으로
kcham k_var_safe_as_str(const kVar* p, kRedStr** o)
{
	if (p->type == KTYPE_STR)
	{
		*o = (kRedStr*)p->rv.p;
		return TRUE;
	}
	else if (p->type == KTYPE_SYMBOL)
	{
		*o = k_redstr_new_sym(p->rv.u);
		return TRUE;
	}
	else
	{
		// 뭡니꺄?
		return FALSE;
	}
}

// 불린 타입
kcham k_var_conv_bool(const kVar* p, kbool* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = FALSE;
			break;
		case KTYPE_POINTER:
			*o = p->rv.p != NULL;
			break;
		case KTYPE_SYMBOL:
			*o = k_atob(k_symunstr(p->rv.u)) != 0;
			break;
		case KTYPE_BOOL:
			*o = p->rv.b;
			break;
		case KTYPE_INT:
			*o = p->rv.i != 0;
			break;
		case KTYPE_LONG:
			*o = p->rv.i64 != 0;
			break;
		case KTYPE_FLOAT:
			*o = !k_eq(p->rv.f, 0.0f);
			break;
		case KTYPE_DOUBLE:
			*o = !k_eq(p->rv.dbl, 0.0);
			break;
		case KTYPE_STR:
			*o = k_atob(((kRedStr*)p->rv.p)->data) != 0;
			break;
		case KTYPE_WCS:
			*o = k_wtob(((kRedWcs*)p->rv.p)->data) != 0;
			break;
		default:
			*o = FALSE;
			return FALSE;
	}
	return TRUE;
}

// 정수
kcham k_var_conv_int(const kVar* p, kint* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = 0;
			break;
		case KTYPE_SYMBOL:
			*o = k_atoi(k_symunstr(p->rv.u));
			break;
		case KTYPE_BOOL:
			*o = p->rv.b;
			break;
		case KTYPE_INT:
			*o = p->rv.i;
			break;
		case KTYPE_LONG:
			*o = (kint)p->rv.i64;
			break;
		case KTYPE_FLOAT:
			*o = (kint)p->rv.f;
			break;
		case KTYPE_DOUBLE:
			*o = (kint)p->rv.dbl;
			break;
		case KTYPE_STR:
			*o = k_atoi(((kRedStr*)p->rv.p)->data);
			break;
		case KTYPE_WCS:
			*o = k_wtoi(((kRedWcs*)p->rv.p)->data);
			break;
		default:
			*o = 0;
			return FALSE;
	}
	return TRUE;
}

// 롱
kcham k_var_conv_long(const kVar* p, klong* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = 0;
			break;
		case KTYPE_SYMBOL:
			*o = k_atol(k_symunstr(p->rv.u));
			break;
		case KTYPE_BOOL:
			*o = p->rv.b;
			break;
		case KTYPE_INT:
			*o = p->rv.i;
			break;
		case KTYPE_LONG:
			*o = p->rv.i64;
			break;
		case KTYPE_FLOAT:
			*o = (klong)p->rv.f;
			break;
		case KTYPE_DOUBLE:
			*o = (klong)p->rv.dbl;
			break;
		case KTYPE_STR:
			*o = k_atol(((kRedStr*)p->rv.p)->data);
			break;
		case KTYPE_WCS:
			*o = k_wtol(((kRedWcs*)p->rv.p)->data);
			break;
		default:
			*o = 0;
			return FALSE;
	}
	return TRUE;
}

// 실수
kcham k_var_conv_float(const kVar* p, float* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = 0.0f;
			break;
		case KTYPE_SYMBOL:
			*o = k_atof(k_symunstr(p->rv.u));
			break;
		case KTYPE_BOOL:
			*o = (float)p->rv.b;
			break;
		case KTYPE_INT:
			*o = (float)p->rv.i;
			break;
		case KTYPE_LONG:
			*o = (float)p->rv.i64;
			break;
		case KTYPE_FLOAT:
			*o = p->rv.f;
			break;
		case KTYPE_DOUBLE:
			*o = (float)p->rv.dbl;
			break;
		case KTYPE_STR:
			*o = k_atof(((kRedStr*)p->rv.p)->data);
			break;
		case KTYPE_WCS:
			*o = k_wtof(((kRedWcs*)p->rv.p)->data);
			break;
		default:
			*o = 0.0f;
			return FALSE;
	}
	return TRUE;
}

// 더블
kcham k_var_conv_double(const kVar* p, double* o)
{
	switch (p->type)
	{
		case KTYPE_NULL:
			*o = 0.0;
			break;
		case KTYPE_SYMBOL:
			*o = k_atod(k_symunstr(p->rv.u));
			break;
		case KTYPE_BOOL:
			*o = p->rv.b;
			break;
		case KTYPE_INT:
			*o = p->rv.i;
			break;
		case KTYPE_LONG:
			*o = (double)p->rv.i64;
			break;
		case KTYPE_FLOAT:
			*o = p->rv.f;
			break;
		case KTYPE_DOUBLE:
			*o = p->rv.dbl;
			break;
		case KTYPE_STR:
			*o = k_atod(((kRedStr*)p->rv.p)->data);
			break;
		case KTYPE_WCS:
			*o = k_wtod(((kRedWcs*)p->rv.p)->data);
			break;
		default:
			*o = 0.0;
			return FALSE;
	}
	return TRUE;
}

// 문자열
kcham k_var_conv_str(const kVar* p, const char** str, kint* len)
{
	if (p->type == KTYPE_SYMBOL)
	{
		if (str)
			*str = k_symunstr(p->rv.u);
		if (len)
			*len = (kint)k_symunlen(p->rv.u);
		return TRUE;
	}
	else if (p->type == KTYPE_STR)
	{
		kRedStr* rs = (kRedStr*)p->rv.p;
		if (str) *str = rs->data;
		if (len) *len = rs->len;
		return TRUE;
	}
	else
	{
		// 뭐짐...
		return FALSE;
	}
}

// 와이드 스트링
kcham k_var_conv_wcs(const kVar* p, const kwchar** str, kint* len)
{
	if (p->type == KTYPE_STR)
	{
		kRedWcs* rw = (kRedWcs*)p->rv.p;
		if (str) *str = rw->data;
		if (len) *len = rw->len;
		return TRUE;
	}
	else
	{
		// 뭐짐...
		return FALSE;
	}
}

// 파라미터
const khParamDesc* k_var_unsafe_param(const kVar* p)
{
	return (const khParamDesc*)p->rv.cp;
}

// 포인터
kpointer k_var_unsafe_ptr(const kVar* p)
{
	return p->rv.p;
}

// 불
kbool k_var_unsafe_bool(const kVar* p)
{
	return p->rv.b;
}

// 정수
kint k_var_unsafe_int(const kVar* p)
{
	return p->rv.i;
}

// 롱
klong k_var_unsafe_long(const kVar* p)
{
	return p->rv.i64;
}

// 실수
float k_var_unsafe_float(const kVar* p)
{
	return p->rv.f;
}

// 더블
double k_var_unsafe_double(const kVar* p)
{
	return p->rv.dbl;
}

// 심볼
kuint k_var_unsafe_sym(const kVar* p)
{
	return p->rv.u;
}

// 심볼
kuint k_var_unsafe_sym_str(const kVar* p, const char** str, kint* len)
{
	if (str)
		*str = k_symunstr(p->rv.u);
	if (len)
		*len = (kint)k_symunlen(p->rv.u);
	return p->rv.u;
}

// 베이스
kBase* k_var_unsafe_base(const kVar* p)
{
	return (kBase*)p->rv.p;
}

// 문자열
const char* k_var_unsafe_str(const kVar* p, kint* len)
{
	if (p->type == KTYPE_SYMBOL)
	{
		if (len)
			*len = (kint)k_symunlen(p->rv.u);
		return k_symunstr(p->rv.u);
	}
	else if (p->type == KTYPE_STR)
	{
		kRedStr* rs = (kRedStr*)p->rv.p;
		if (len)
			*len = rs->len;
		return rs->data;
	}
	else
	{
		// 뭐짐...
		return NULL;
	}
}

// 유니코드 문자열
const kwchar* k_var_unsafe_wcs(const kVar* p, kint* len)
{
	if (p->type == KTYPE_STR)
	{
		kRedWcs* rw = (kRedWcs*)p->rv.p;
		if (len) *len = rw->len;
		return rw->data;
	}
	else
	{
		// 뭐짐...
		return NULL;
	}
}


//////////////////////////////////////////////////////////////////////////
// 스택

// 탑
void k_scv_move_top(kScv* p, kVar* v)
{
	p->top = (ksize_t)(v - p->data);
}

// 어디
kVar* k_scv_at(const kScv* p, kint at)
{
	return &p->data[at];
}

// 탑
kVar* k_scv_at_top(const kScv* p)
{
	return &p->data[p->top];
}

// 베이스
kVar* k_scv_at_base(const kScv* p)
{
	return &p->data[p->base];
}

// 컨테이너
kVar* k_scv_at_ctnr(const kScv* p)
{
	return &p->data[0];
}

// 펍
kVar* k_scv_at_pub(const kScv* p)
{
	return &p->data[1];
}

// 셀프
kVar* k_scv_at_self(const kScv* p)
{
	return &p->data[p->base - 2];
}

// 함수
kVar* k_scv_at_fn(const kScv* p)
{
	return &p->data[p->base - 1];
}

// 인수
kVar* k_scv_arg(const kScv* p, kint nth)
{
	return &p->data[p->base + nth];
}

// 인수 개수
kint k_scv_arity(const kScv* p)
{
	return (kint)p->arity;
}

// 외부
kpointer k_scv_aud(const kScv* p)
{
	return p->aud;
}

// 뽑기
kVar* k_scv_pop(kScv* p)
{
	return &p->data[--p->top];
}

// 뽑기
void k_scv_pop_ret(kScv* p, kVar* ret)
{
	k_assert_0(ret != NULL);
	*ret = p->data[--p->top];
}

// 넣기
void k_scv_agn(kScv* p, const kVar* v)
{
	p->data[p->top++] = *v;
}

// 널기
void k_scv_agn_base(kScv* p, kBase* v)
{
	k_var_agn_base(&p->data[p->top++], v);
}

// 넣기
void k_scv_agn_type(kScv* p, kType type, kBase* ptr)
{
	k_var_agn_type(&p->data[p->top++], type, ptr);
}

// 바
void k_scv_push(kScv* p, const kVar* v)
{
	p->data[p->top] = *v;
	k_var_load(&p->data[p->top]);
	p->top++;
}

// 안전
void k_scv_push_safe(kScv* p, const kVar* v)
{
	if (!v)
		k_var_zero(&p->data[p->top++]);
	else
	{
		p->data[p->top] = *v;
		k_var_load(&p->data[p->top]);
		p->top++;
	}
}

// 자기를 다시 넣거나, 새로운 자기를 설정
void k_scv_push_self(kScv* p, const kVar* self_or_null)
{
	if (self_or_null)
	{
		k_var_unload(&p->data[p->base - 2]);
		p->data[p->base - 2] = *self_or_null;
		k_var_load(&p->data[p->base - 2]);
	}
	else
	{
		k_var_load(&p->data[p->base - 2]);
		p->data[p->top++] = p->data[p->base - 2];
	}
}

// 베이스, 타입
void k_scv_push_type(kScv* p, kType type, kBase* ptr)
{
	k_var_set_type(&p->data[p->top++], type, ptr);
}

// 널
void k_scv_push_null(kScv* p)
{
	k_var_set_null(&p->data[p->top++]);
}

// 파라미터
void k_scv_push_param(kScv* p, const khParamDesc* v)
{
	k_var_set_param(&p->data[p->top++], v);
}

// 포인터
void k_scv_push_ptr(kScv* p, kpointer v)
{
	k_var_set_ptr(&p->data[p->top++], v);
}

// 불
void k_scv_push_bool(kScv* p, kbool v)
{
	k_var_set_bool(&p->data[p->top++], v);
}

// 정수
void k_scv_push_int(kScv* p, kint v)
{
	k_var_set_int(&p->data[p->top++], v);
}

// 롱
void k_scv_push_long(kScv* p, klong v)
{
	k_var_set_long(&p->data[p->top++], v);
}

// 싨
void k_scv_push_float(kScv* p, float v)
{
	k_var_set_float(&p->data[p->top++], v);
}

// 덥
void k_scv_push_double(kScv* p, double v)
{
	k_var_set_double(&p->data[p->top++], v);
}

// 베이스
void k_scv_push_base(kScv* p, kBase* v)
{
	k_var_set_base(&p->data[p->top++], v);
}

// 스트링
void k_scv_push_str(kScv* p, const char* str, kint len)
{
	k_var_set_str(&p->data[p->top++], str, len);
}

// 와이드 스트링
void k_scv_push_wcs(kScv* p, const kwchar* str, kint len)
{
	k_var_set_wcs(&p->data[p->top++], str, len);
}

// 심볼
void k_scv_push_sym(kScv* p, kuint v)
{
	k_var_set_sym(&p->data[p->top++], v);
}

// 심볼
void k_scv_push_sym_flex(kScv* p, const char* v)
{
	k_var_set_sym_flex(&p->data[p->top++], v);
}

// 심볼
void k_scv_push_sym_static(kScv* p, const char* v)
{
	k_var_set_sym_static(&p->data[p->top++], v);
}

// 트랑
kcham k_scv_push_try_sym(kScv* p, const char* v)
{
	return k_var_try_sym(&p->data[p->top++], v);
}

// 베이스, 타입
kcham k_scv_arg_type(const kScv* p, kint nth, kType type, kBase** v)
{
	return nth < p->arity && k_var_safe_type(&p->data[p->base + nth], type, v);
}

// 파람
kcham k_scv_arg_param(const kScv* p, kint nth, khParamDesc** v)
{
	return nth < p->arity && k_var_safe_param(&p->data[p->base + nth], v);
}

// 포인터
kcham k_scv_arg_ptr(const kScv* p, kint nth, kpointer* v)
{
	return nth < p->arity && k_var_safe_ptr(&p->data[p->base + nth], v);
}

// 불
kcham k_scv_arg_bool(const kScv* p, kint nth, kbool* v)
{
	return nth < p->arity && k_var_safe_bool(&p->data[p->base + nth], v);
}

// 정수
kcham k_scv_arg_int(const kScv* p, kint nth, kint* v)
{
	return nth < p->arity && k_var_safe_int(&p->data[p->base + nth], v);
}

// 롱
kcham k_scv_arg_long(const kScv* p, kint nth, klong* v)
{
	return nth < p->arity && k_var_safe_long(&p->data[p->base + nth], v);
}

// 실수
kcham k_scv_arg_float(const kScv* p, kint nth, float* v)
{
	return nth < p->arity && k_var_safe_float(&p->data[p->base + nth], v);
}

// 더블
kcham k_scv_arg_double(const kScv* p, kint nth, double* v)
{
	return nth < p->arity && k_var_safe_double(&p->data[p->base + nth], v);
}

// 심볼
kcham k_scv_arg_sym(const kScv* p, kint nth, kuint* v)
{
	return nth < p->arity && k_var_safe_sym(&p->data[p->base + nth], v);
}

// 심볼
kcham k_scv_arg_sym_str(const kScv* p, kint nth, const char** str,
	kint* len)
{
	return nth < p->arity
		&& k_var_safe_sym_str(&p->data[p->base + nth], str, len);
}

// 베이스
kcham k_scv_arg_base(const kScv* p, kint nth, kBase** v)
{
	return nth < p->arity && k_var_safe_base(&p->data[p->base + nth], v);
}

// 숫자
kcham k_scv_arg_num(const kScv* p, kint nth, double* v)
{
	return nth < p->arity && k_var_conv_double(&p->data[p->base + nth], v);
}

// 문자열 타입
kcham k_scv_arg_str(const kScv* p, kint nth, const char** str, kint* len)
{
	return nth < p->arity && k_var_conv_str(&p->data[p->base + nth], str, len);
}

// 와이드 문자열 타입
kcham k_scv_arg_wcs(const kScv* p, kint nth, const kwchar** str,
	kint* len)
{
	return nth < p->arity && k_var_conv_wcs(&p->data[p->base + nth], str, len);
}

// 불 타입
kcham k_scv_arg_type_bool(const kScv* p, kint nth, kbool* v)
{
	return nth < p->arity && k_var_conv_bool(&p->data[p->base + nth], v);
}

// 정수 타입
kcham k_scv_arg_type_int(const kScv* p, kint nth, kint* v)
{
	return nth < p->arity && k_var_conv_int(&p->data[p->base + nth], v);
}

// 롱 타입
kcham k_scv_arg_type_long(const kScv* p, kint nth, klong* v)
{
	return nth < p->arity && k_var_conv_long(&p->data[p->base + nth], v);
}

// 실수 타입
kcham k_scv_arg_type_float(const kScv* p, kint nth, float* v)
{
	return nth < p->arity && k_var_conv_float(&p->data[p->base + nth], v);
}

// 더블 타입
kcham k_scv_arg_type_double(const kScv* p, kint nth, double* v)
{
	return nth < p->arity && k_var_conv_double(&p->data[p->base + nth], v);
}

// 베이스, 타입
kcham k_scv_self_type(const kScv* p, kType type, kBase** ptr)
{
	return k_var_safe_type(&p->data[p->base - 2], type, ptr);
}

// 파람
kcham k_scv_self_param(const kScv* p, khParamDesc** v)
{
	return k_var_safe_param(&p->data[p->base - 2], v);
}

// 포인터
kcham k_scv_self_ptr(const kScv* p, kpointer* v)
{
	return k_var_safe_ptr(&p->data[p->base - 2], v);
}

// 불
kcham k_scv_self_bool(const kScv* p, kbool* v)
{
	return k_var_safe_bool(&p->data[p->base - 2], v);
}

// 정수
kcham k_scv_self_int(const kScv* p, kint* v)
{
	return k_var_safe_int(&p->data[p->base - 2], v);
}

// 롱
kcham k_scv_self_long(const kScv* p, klong* v)
{
	return k_var_safe_long(&p->data[p->base - 2], v);
}

// 실수
kcham k_scv_self_float(const kScv* p, float* v)
{
	return k_var_safe_float(&p->data[p->base - 2], v);
}

// 더블
kcham k_scv_self_double(const kScv* p, double* v)
{
	return k_var_safe_double(&p->data[p->base - 2], v);
}

// 심볼
kcham k_scv_self_sym(const kScv* p, kuint* v)
{
	return k_var_safe_sym(&p->data[p->base - 2], v);
}

// 심볼
kcham k_scv_self_sym_str(const kScv* p, const char** str, kint* len)
{
	return k_var_safe_sym_str(&p->data[p->base - 2], str, len);
}

// 베이스
kcham k_scv_self_base(const kScv* p, kBase** v)
{
	return k_var_safe_base(&p->data[p->base - 2], v);
}

// 숫자
kcham k_scv_self_num(const kScv* p, double* v)
{
	return k_var_conv_double(&p->data[p->base - 2], v);
}

// 스트링
kcham k_scv_self_str(const kScv* p, const char** str, kint* len)
{
	return k_var_conv_str(&p->data[p->base - 2], str, len);
}

// 와이드
kcham k_scv_self_wcs(const kScv* p, const kwchar** str, kint* len)
{
	return k_var_conv_wcs(&p->data[p->base - 2], str, len);
}

// 불
kcham k_scv_self_type_bool(const kScv* p, kbool* v)
{
	return k_var_conv_bool(&p->data[p->base - 2], v);
}

// 정수
kcham k_scv_self_type_int(const kScv* p, kint* v)
{
	return k_var_conv_int(&p->data[p->base - 2], v);
}

// 롱
kcham k_scv_self_type_long(const kScv* p, klong* v)
{
	return k_var_conv_long(&p->data[p->base - 2], v);
}

// 실수
kcham k_scv_self_type_float(const kScv* p, float* v)
{
	return k_var_conv_float(&p->data[p->base - 2], v);
}

// 더블
kcham k_scv_self_type_double(const kScv* p, double* v)
{
	return k_var_conv_double(&p->data[p->base - 2], v);
}

// 스트링
const char* k_scv_self_tos(const kScv* p, char* buf, kint size, kint* len)
{
	return k_var_tos(&p->data[p->base - 2], buf, size, len);
}

// 베이스
kBase* k_scv_unsafe_self_base(const kScv* p)
{
	return k_var_unsafe_base(&p->data[p->base - 2]);
}

// 문자열
const char* k_scv_unsafe_self_str(const kScv* p, kint* len)
{
	return k_var_unsafe_str(&p->data[p->base - 2], len);
}

// 와이드 문자열
const kwchar* k_scv_unsafe_self_wcs(const kScv* p, kint* len)
{
	return k_var_unsafe_wcs(&p->data[p->base - 2], len);
}

// 인수 분석
kcham k_scv_arg_vascanf(kScv* p, const char* fmt, va_list va)
{
	kVar* ae;
	kVar* ap;
	char ch;
	kbool req;
	kany64 vv;

	ae = &p->data[p->base + p->arity];
	ap = &p->data[p->base];
	req = TRUE;

	while ((ch = *fmt++) != '\0')
	{
		if (k_isspace(ch))
			continue;

		if (ch == '-')
		{
			// '-' 뒤에 있는 것은 반드시 필요한 것은 아님
			// 즉 선택적 인수
			req = FALSE;
			continue;
		}

		if (ap == ae)
		{
			if (req)
			{
				// 필요 인수가 있는데, 이미 개수 만큼 함
				// -> 당근 오류
				return FALSE;
			}
			break;
		}

		switch (ch)
		{
			// 변환 불가
			case 'b':
				if (!k_var_safe_bool(ap, va_arg(va, kbool*)))
					return FALSE;
				break;

			case 'c':
				if (!k_var_safe_int(ap, &vv.i))
					return FALSE;
				*va_arg(va, kint*) = (kbyte)vv.i;
				break;

			case 'h':
				if (!k_var_safe_int(ap, &vv.i))
					return FALSE;
				*va_arg(va, kshort*) = (kshort)vv.i;
				break;

			case 'i':
				if (!k_var_safe_int(ap, va_arg(va, kint*)))
					return FALSE;
				break;

			case 'l':
				if (!k_var_safe_long(ap, va_arg(va, klong*)))
					return FALSE;
				break;

			case 'f':
				if (!k_var_safe_float(ap, va_arg(va, float*)))
					return FALSE;
				break;

			case 'd':
				if (!k_var_safe_double(ap, va_arg(va, double*)))
					return FALSE;
				break;

				// 변환 가능
			case 'B':
				if (!k_var_conv_bool(ap, va_arg(va, kbool*)))
					return FALSE;
				break;

			case 'C':
				if (!k_var_conv_int(ap, &vv.i))
					return FALSE;
				*va_arg(va, kint*) = (kbyte)vv.i;
				break;

			case 'H':
				if (!k_var_conv_int(ap, &vv.i))
					return FALSE;
				*va_arg(va, kshort*) = (kshort)vv.i;
				break;

			case 'I':
				if (!k_var_conv_int(ap, va_arg(va, kint*)))
					return FALSE;
				break;

			case 'L':
				if (!k_var_conv_long(ap, va_arg(va, klong*)))
					return FALSE;
				break;

			case 'F':
				if (!k_var_conv_float(ap, va_arg(va, float*)))
					return FALSE;
				break;

			case 'D':
				if (!k_var_conv_double(ap, va_arg(va, double*)))
					return FALSE;
				break;

			case 'z':
			case 'o':
				// 베이스
				if (!k_var_safe_base(ap, va_arg(va, kBase**)))
					return FALSE;
				break;

			case 'a':
				// 문자열
				if (!k_var_safe_type(ap, KTYPE_STR, va_arg(va, kBase**)))
					return FALSE;
				break;

			case 'w':
				// 와이드
				if (!k_var_safe_type(ap, KTYPE_WCS, va_arg(va, kBase**)))
					return FALSE;
				break;

			case 't':
				// 테이브
				if (!k_var_safe_type(ap, KTYPE_TBL, va_arg(va, kBase**)))
					return FALSE;
				break;

			case 'n':
				// 함수
				if (!k_var_safe_type(ap, KTYPE_FN, va_arg(va, kBase**)))
					return FALSE;
				break;

			case 's':
				// 문자열
				if (!k_var_conv_str(ap, va_arg(va, const char**), NULL))
					return FALSE;
				break;

			case 'S':
				if (!k_var_conv_wcs(ap, va_arg(va, const kwchar**), NULL))
					return FALSE;
				break;

			case 'v':
				// 변수
				*va_arg(va, kVar*) = *ap;
				break;

				//
			case '*':
			case '_':
				break;

			default:
				return FALSE;
		}

		ap++;
	}

	return TRUE;
}

// 인수 분석
kcham k_scv_arg_scanf(kScv* p, const char* fmt, ...)
{
	va_list va;
	kcham ret;

	va_start(va, fmt);
	ret = k_scv_arg_vascanf(p, fmt, va);
	va_end(va);

	return ret;
}
